package com.sunmi.sbs.commons.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class JsonComparison {
    public static String JsonCompare(JSONObject obj, boolean isSort) {
        JSONArray diffList = new JSONArray();
        JSONObject doris = obj.getJSONObject("doris");
        JSONObject model = obj.getJSONObject("model");

        List<String> differences = findDifferences(doris, model, isSort);
        int diffCount = differences.size();
        int denominator = Math.max(doris.size(), model.size()); // 取最大一方作为分母

        // 处理分母为0的极端情况（防止除零异常）
        if (denominator == 0) denominator = 1;

        String mark = "";
        if (diffCount > 0) {
            double percentage = (double) diffCount / denominator * 100;
            if (percentage > 50) {
                mark = "P0";
            } else if (percentage >= 30) {
                mark = "P1";
            } else {
                mark = "P2";
            }
            mark = " [标记：" + mark + "（差异率" + String.format("%.2f%%", percentage) + "）]";
        }

        if (differences.isEmpty()) {
            return "doris 和 model 对象没有差异。";
        } else {
            for (String diff : differences) {
                diffList.add(diff);
            }
            return mark + "  doris 和 model 对象的差异如下：" + diffList.toJSONString();
        }
    }

    public static List<String> findDifferences(JSONObject doris, JSONObject model, boolean isSort) {
        List<String> differences = new ArrayList<>();
        compareObjects(doris, model, "", differences, isSort);
        return differences;
    }

    private static void compareObjects(JSONObject doris, JSONObject model, String path, List<String> differences, boolean isSort) {
        if (doris == null && model == null) {
            return;
        }

        // 处理doris为null而model不为null的情况
        if (doris == null) {
            for (String key : model.keySet()) {
                String newPath = path.isEmpty() ? key : path + "." + key;
                differences.add("在 " + newPath + " 处，doris 中不存在该键。");
            }
            return;
        }

        // 处理model为null而doris不为null的情况
        if (model == null) {
            // 只有当model为null时，才记录doris中存在但model中不存在的key
            for (String key : doris.keySet()) {
                String newPath = path.isEmpty() ? key : path + "." + key;
                differences.add("在 " + newPath + " 处，model 中不存在该键。");
            }
            return;
        }

        // 检查model中是否有doris中不存在的key
        boolean hasModelKeyMissingInDoris = false;
        for (String key : model.keySet()) {
            if (!doris.containsKey(key)) {
                String newPath = path.isEmpty() ? key : path + "." + key;
                differences.add("在 " + newPath + " 处，doris 中不存在该键。");
                hasModelKeyMissingInDoris = true;
            }
        }

        // 只比对doris中存在的key
        for (String key : doris.keySet()) {
            String newPath = path.isEmpty() ? key : path + "." + key;

            // 如果model中不包含该key
            if (!model.containsKey(key)) {
                // 只有当model中有key在doris中不存在时，才记录这个差异
                if (hasModelKeyMissingInDoris) {
                    differences.add("在 " + newPath + " 处，model 中不存在该键。");
                }
                continue;
            }

            Object dorisValue = doris.get(key);
            Object modelValue = model.get(key);

            // 如果两个值都为null，继续下一个key
            if (dorisValue == null && modelValue == null) {
                continue;
            }

            // 如果dorisValue为null而modelValue不为null，记录差异并继续下一个key
            if (dorisValue == null) {
                differences.add("在 " + newPath + " 处，doris 值为 null，model = " + modelValue);
                continue;
            }

            // 如果modelValue为null而dorisValue不为null，记录差异并继续下一个key
            if (modelValue == null) {
                differences.add("在 " + newPath + " 处，model 值为 null，doris = " + dorisValue);
                continue;
            }

            // 递归比较JSONObject
            if (dorisValue instanceof JSONObject && modelValue instanceof JSONObject) {
                compareObjects((JSONObject) dorisValue, (JSONObject) modelValue, newPath, differences, isSort);
            }
            // 递归比较JSONArray
            else if (dorisValue instanceof JSONArray && modelValue instanceof JSONArray) {
                compareArrays((JSONArray) dorisValue, (JSONArray) modelValue, newPath, differences, isSort);
            }
            // 直接比较基本类型
            else if (!dorisValue.equals(modelValue)) {
                differences.add("在 " + newPath + " 处，值不同：doris = " + dorisValue + ", model = " + modelValue);
            }
        }
    }

    private static void compareArrays(JSONArray dorisArray, JSONArray modelArray, String path, List<String> differences, boolean isSort) {
        if (dorisArray == null && modelArray == null) {
            return;
        }

        // 处理dorisArray为null而modelArray不为null的情况
        if (dorisArray == null) {
            differences.add("在 " + path + " 处，doris 数组为 null，model 数组长度 = " + modelArray.size());
            return;
        }

        // 处理modelArray为null而dorisArray不为null的情况
        if (modelArray == null) {
            differences.add("在 " + path + " 处，model 数组为 null，doris 数组长度 = " + dorisArray.size());
            return;
        }

        JSONArray sortedDorisArray = dorisArray;
        JSONArray sortedModelArray = modelArray;

        // 如果需要排序，对数组进行排序
        if (isSort) {
            sortedDorisArray = sortJsonArray(dorisArray);
            sortedModelArray = sortJsonArray(modelArray);
        }

        // 比较数组长度
        if (sortedDorisArray.size() != sortedModelArray.size()) {
            differences.add("在 " + path + " 处，数组长度不同：doris 数组长度 = " + sortedDorisArray.size() + ", model 数组长度 = " + sortedModelArray.size());
        }
        // 数组长度相同，逐个比较元素
        else {
            for (int i = 0; i < sortedDorisArray.size(); i++) {
                String newPath = path + "[" + i + "]";
                Object dorisValue = sortedDorisArray.get(i);
                Object modelValue = sortedModelArray.get(i);

                // 如果两个值都为null，继续下一个元素
                if (dorisValue == null && modelValue == null) {
                    continue;
                }

                // 如果dorisValue为null而modelValue不为null，记录差异并继续下一个元素
                if (dorisValue == null) {
                    differences.add("在 " + newPath + " 处，doris 值为 null，model = " + modelValue);
                    continue;
                }

                // 如果modelValue为null而dorisValue不为null，记录差异并继续下一个元素
                if (modelValue == null) {
                    differences.add("在 " + newPath + " 处，model 值为 null，doris = " + dorisValue);
                    continue;
                }

                // 递归比较JSONObject
                if (dorisValue instanceof JSONObject && modelValue instanceof JSONObject) {
                    compareObjects((JSONObject) dorisValue, (JSONObject) modelValue, newPath, differences, isSort);
                }
                // 递归比较JSONArray
                else if (dorisValue instanceof JSONArray && modelValue instanceof JSONArray) {
                    compareArrays((JSONArray) dorisValue, (JSONArray) modelValue, newPath, differences, isSort);
                }
                // 直接比较基本类型
                else if (!dorisValue.equals(modelValue)) {
                    differences.add("在 " + newPath + " 处，值不同：doris = " + dorisValue + ", model = " + modelValue);
                }
            }
        }
    }

    private static JSONArray sortJsonArray(JSONArray array) {
        if (array == null) {
            return new JSONArray();
        }
        List<Object> list = new ArrayList<>(array);
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 == null && o2 == null) {
                    return 0;
                }
                if (o1 == null) {
                    return -1;
                }
                if (o2 == null) {
                    return 1;
                }
                if (o1 instanceof JSONObject && o2 instanceof JSONObject) {
                    return ((JSONObject) o1).toJSONString().compareTo(((JSONObject) o2).toJSONString());
                }
                if (o1 instanceof String && o2 instanceof String) {
                    return ((String) o1).compareTo((String) o2);
                }
                if (o1 instanceof Number && o2 instanceof Number) {
                    return Double.compare(((Number) o1).doubleValue(), ((Number) o2).doubleValue());
                }
                return 0;
            }
        });
        return new JSONArray(list);
    }
}